package com.micro.config.security;

import com.micro.config.Filter.JwtFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;


import java.util.Arrays;
import java.util.List;

import static org.springframework.security.config.Customizer.withDefaults;

@EnableWebSecurity
//开启全局方法权限控制
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{

    @Autowired
    private JwtFilter jwtFilter;


    private final List<String> permitAllEndpoints = Arrays.asList(
            /*
            * swaggerUI的白名单路径
            * */
            "/v2/api-docs",
            "/configuration/ui",
            "/swagger-resources/**",
            "/configuration/security",
            "/swagger-ui.html",
            "/webjars/**",
            "/doc.html",
            /*
            * 去除context-path: /demo
            * */
            "/user/list",
            "/register",
            "/register1"
    );

    /*
    * 配置查询数据库的方法
    * */

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 注入AuthenticationManager到spring容器中，用于用户登录时调用方法验证
     *
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }


    /*
    * 权限授权配置
    * */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        super.configure(auth);
    }

    // 配置Web请求的安全性
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                /*
                *在配置中使用自定义的UserDetailsService，可以实现以下功能：
                *    根据提供的用户名从数据库或其他数据源中加载用户信息。
                *    验证用户提供的密码，并返回匹配的用户对象。
                *    返回用户的角色和权限信息，以便进行访问控制。
                * 通过设置自定义的UserDetailsService，我们可以确保应用程序中的用户认证和授权逻辑是安全且符合业务需求的。
                * */
//                .userDetailsService(dbUserDetailsManager)
                /*
                * 通过.authorizeRequests()配置授权规则。
                * .antMatchers(permitAllEndpoints.toArray(new String[0])).permitAll()允许指定的端点无需认证即可访问，
                * .anyRequest().authenticated()要求其他所有请求必须经过认证
                * */
                .authorizeRequests(
                        auth -> auth
                                .antMatchers(permitAllEndpoints.toArray(new String[0])).permitAll()
                                .anyRequest()
                                .authenticated()
                )
                .formLogin(form -> {
                    form
                            .loginPage("/login").permitAll() //登录页面无需授权即可访问
                            .usernameParameter("username") //自定义表单用户名参数，默认是username
                            .passwordParameter("password") //自定义表单密码参数，默认是password
                            .failureUrl("/login?error") //登录失败的返回地址
                            .successHandler(new MyAuthenticationSuccessHandler())
                            .failureHandler(new MyAuthenticationFailureHandler())
                    ;
                })
                .httpBasic()
                .and()
                .csrf().disable();//基本授权方式
        http
                .logout(logout ->{
                    logout.logoutSuccessHandler(new MyLogoutSuccessHandler()); //注销成功时的处理
        })
                .exceptionHandling(exception  -> {
                    exception.authenticationEntryPoint(new MyAuthenticationEntryPoint());//请求未认证的接口
                    exception.accessDeniedHandler(new MyAccessDeniedHandler());
        })
                .sessionManagement(session -> {
                    session.maximumSessions(1).expiredSessionStrategy(new MySessionInformationExpiredStrategy());
                })
                .cors(withDefaults());//跨域配置
        http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
    }


}
